<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * reduce方法（是数组的方法）
    *   功能：迭代（内置遍历的功能），将数组每一项进行运算，上次运算结果参与到下次运算中，直至迭代结束
    *   参数：
    *       一个参数：回调函数(首次迭代以数组第一项作为迭代体，以第二项作为第一次迭代，迭代次数比数组长度少1)
    *
    *       两个参数：
    *           1.回调函数（迭代的方法）接收四个参数(首次迭代以传入的初始值为迭代体，迭代次数与数组长度一致)
    *               迭代体total
    *               数组每项元素item
    *               每项元素下标index
    *               数组arr
    *               回调函数返回值：返回单次的迭代结果
    *           2.迭代体的初始值：数字相加就初始值为0,相乘就初始值为1，字符串拼接就初始值为空字符串""，如果要生成对象就初始值为空对象{}
    *
    *       reduce的返回值：因为回调函数只返回单次迭代结果，所以reduce返回遍历之后整体最终的迭代结果
    *
    * */

    function myReduce(arr,callback){ //reduce方法接收的形参 数组 回调函数
        if(arguments.length < 2){//如果传入参数不足，抛出一个错误
            throw new Error("参数不齐")
            return //结束函数
        }
        //初始化迭代体 result（默认值为null） 根据传了多少参数判断接下来result应该为什么值
        let result = null
        let start = 0 //迭代循环的开始下标，初始值默认为0
        //怎么判断传了几个参数？
        if(arguments.length === 2){//一个参数的情况，2中包含了数组，数组不算，只算回调函数，则迭代体的初始值为数组第一项
            result = arr[0] //迭代体为数组下标为0第一项
            start = 1 //循环中回调函数开始迭代的元素下标 因为没有初始值 所以迭代体就把数组第一项占了做初始值 迭代就是 迭代体与数组每一项进行操作
        }else{//两个参数情况 一定传了初始值
            result = arguments[2] //result就等于传入的初始值
        }
        //上面这些代码都在做一件事，判断传入参数的情况
        //接下来就需要进行迭代,考虑迭代初始值是从哪开始的问题
        for(let i = start;i < arr.length;i++){
            result = callback(result,arr[i],i,arr) //迭代体 item index 数组 将回调函数操作的单次的迭代结果 返回出来赋值给新的迭代体 进行下次迭代
            //先前的迭代体在经过回调函数的迭代操作后 成迭代结果 并将在下次迭代中作为新的迭代体 带入下列例子中理解更好
        }
        return result
    }
    let arr = [1,2,3,4]
    let fn = function (total,item){ //迭代体 数组元素
        return total + item //将迭代结果返回出去
    }
    let s = myReduce(arr,fn)
    console.log(s)
    let s1 = myReduce(arr,fn,"")
    console.log(s1)

</script>
</body>
</html>